<?php

namespace common\base;

use Yii;
use yii\db\Exception;

/**
 * Model is the base class for data models.
 *
 * @author emhome <emhome@163.com>
 * @since 1.0
 */
class Model extends \yii\base\Model {

    use \common\traits\ModelErrors;

//    use \common\traits\DataPierces;

    const TRANS_FUNC_PREFIX = 'transact';

    /**
     * @var array|\common\base\Security the security used to safe data attribute values into displayable texts.
     * This can be either an instance of [[Security]] or an configuration array for creating the [[Security]]
     * instance. If this property is not set, the "security" application component will be used.
     */
    private $_security;

    /**
     * Initializes the grid view.
     * This method will initialize required property values and instantiate [[columns]] objects.
     */
    public function init() {
        parent::init();
        $this->setSecurity();
    }

    public function setSecurity($configure = null) {
        if (empty($configure)) {
            $this->_security = Yii::$app->getSecurity();
        } else {
            $this->_security = Yii::createObject($configure);
        }
    }

    public function security() {
        return $this->_security;
    }

    /**
     * AR事务封装
     *
     * @param $method
     * @param null $error
     * @return mixed|void
     * @throws ModelHttpException
     */
    public function executeTransaction($method, $error = null) {
        $transaction = Yii::$app->db->beginTransaction();
        try {
            $executeResult = call_user_func(array($this, self::TRANS_FUNC_PREFIX . ucfirst($method)));
            $transaction->commit();
        } catch (Exception $e) {
            $transaction->rollBack();
            if ($error !== null) {
                return $error;
            }
            $msg = $e->getMessage();
            if (YII_DEBUG) {
                Yii::error($e->errorInfo);
            }
            return $this->saveError($msg, false);
        }
        return $executeResult;
    }

    /**
     * 分离增删交叉数据集
     * @param array $old 原始数据
     * @param array $now 当前数据
     * @return array
     */
    public function divideViaData($old, $now) {
        $intersect = array_intersect($old, $now);
        $remove = array_diff($old, $intersect);
        $create = array_diff($now, $intersect);
        return compact('remove', 'create');
    }

    /**
     * Populates the model with input data.
     */
    public function getCommonCache() {
        if (Yii::$app->has('commonCache')) {
            return Yii::$app->commonCache;
        }
        return Yii::$app->cache;
    }

    /**
     * Returns the attribute titles.
     *
     * Attribute labels are mainly used for display purpose. For example, given an attribute
     * `firstName`, we can declare a label `First Name` which is more user-friendly and can
     * be displayed to end users.
     *
     * By default an attribute label is generated using [[generateAttributeLabel()]].
     * This method allows you to explicitly specify attribute labels.
     *
     * Note, in order to inherit labels defined in the parent class, a child class needs to
     * merge the parent labels with child labels using functions such as `array_merge()`.
     *
     * @return array attribute labels (name => label)
     * @see generateAttributeLabel()
     */
    public function attributeTitles() {
        return [];
    }

    /**
     * Returns the text title for the specified attribute.
     * @param string $attribute the attribute name
     * @return string the attribute label
     * @see generateAttributeLabel()
     * @see attributeLabels()
     */
    public function getAttributeTitle($attribute) {
        $titles = $this->attributeTitles();
        return isset($titles[$attribute]) ? $titles[$attribute] : $this->getAttributeLabel($attribute);
    }

    /**
     * Returns the attribute titles.
     *
     * Attribute labels are mainly used for display purpose. For example, given an attribute
     * `firstName`, we can declare a label `First Name` which is more user-friendly and can
     * be displayed to end users.
     *
     * By default an attribute label is generated using [[generateAttributeLabel()]].
     * This method allows you to explicitly specify attribute labels.
     *
     * Note, in order to inherit labels defined in the parent class, a child class needs to
     * merge the parent labels with child labels using functions such as `array_merge()`.
     *
     * @return array attribute labels (name => label)
     * @see generateAttributeLabel()
     */
    public function attributePlaceholders() {
        return [];
    }

    /**
     * Returns the text title for the specified attribute.
     * @param string $attribute the attribute name
     * @return string the attribute label
     * @see generateAttributeLabel()
     * @see attributeLabels()
     */
    public function getAttributePlaceholder($attribute) {
        $placeholder = $this->attributePlaceholders();
        return isset($placeholder[$attribute]) ? $placeholder[$attribute] : '';
    }

}
